﻿using System;
using System.Runtime.Serialization;

namespace HYCodeBase.Algorithm.Octree.Data
{
	[DataContract]
	public struct Point
	{
        [DataMember]
        public float X;// { get; set; }

        [DataMember]
        public float Y;// { get; set; }

        [DataMember]
        public float Z;// { get; set; }

		public float Magnitude
		{
			get
			{
				return (float)System.Math.Sqrt((double)(this.X * this.X + this.Y * this.Y + this.Z * this.Z));
			}
		}

		public float SqrMagnitude
		{
			get
			{
				return this.X * this.X + this.Y * this.Y + this.Z * this.Z;
			}
		}

		public Point Normalized
		{
			get
			{
				Point point = this;
				return point.Normalized;
			}
		}

		public Point(float x, float y, float z = 0f)
		{
			this.X = x;
			this.Y = y;
			this.Z = z;
		}

		public void Normalize()
		{
			float magnitude = this.Magnitude;
			if (magnitude > 1E-05f)
			{
				this /= magnitude;
				return;
			}
			this = Point.Zero;
		}

		public override int GetHashCode()
		{
			return this.X.GetHashCode() ^ this.Y.GetHashCode() << 2 ^ this.Z.GetHashCode() >> 2;
		}

		public override bool Equals(object other)
		{
			bool result;
			if (!(other is Point))
			{
				result = false;
			}
			else
			{
				Point point = (Point)other;
				result = (this.X.Equals(point.X) && this.Y.Equals(point.Y) && this.Z.Equals(point.Z));
			}
			return result;
		}

		public override string ToString()
		{
			return string.Format("({0:F1}, {1:F1}, {2:F1})", this.X, this.Y, this.Z);
		}

		public string ToString(string format)
		{
			return string.Format("({0}, {1}, {2})", this.X.ToString(format), this.Y.ToString(format), this.Z.ToString(format));
		}

		public static float Distance(Point a, Point b)
		{
			Point point = new Point(a.X - b.X, a.Y - b.Y, a.Z - b.Z);
			return (float)System.Math.Sqrt((double)(point.X * point.X + point.Y * point.Y + point.Z * point.Z));
		}

		public static Point Scale(Point a, Point b)
		{
			return new Point(a.X * b.X, a.Y * b.Y, a.Z * b.Z);
		}

		public static Point Cross(Point a, Point b)
		{
			return new Point(a.Y * b.Z - a.Z * b.Y, a.Z * b.X - a.X * b.Z, a.X * b.Y - a.Y * b.X);
		}

		public static float Dot(Point a, Point b)
		{
			return a.X * b.X + a.Y * b.Y + a.Z * b.Z;
		}

		public static Point Min(Point a, Point b)
		{
			return new Point(System.Math.Min(a.X, b.X), System.Math.Min(a.Y, b.Y), System.Math.Min(a.Z, b.Z));
		}

		public static Point Max(Point a, Point b)
		{
			return new Point(System.Math.Max(a.X, b.X), System.Math.Max(a.Y, b.Y), System.Math.Max(a.Z, b.Z));
		}

		public static Point operator +(Point a, Point b)
		{
			return new Point(a.X + b.X, a.Y + b.Y, a.Z + b.Z);
		}

		public static Point operator -(Point a, Point b)
		{
			return new Point(a.X - b.X, a.Y - b.Y, a.Z - b.Z);
		}

		public static Point operator -(Point a)
		{
			return new Point(-a.X, -a.Y, -a.Z);
		}

		public static Point operator *(Point a, float d)
		{
			return new Point(a.X * d, a.Y * d, a.Z * d);
		}

		public static Point operator *(float d, Point a)
		{
			return new Point(a.X * d, a.Y * d, a.Z * d);
		}

		public static Point operator /(Point a, float d)
		{
			return new Point(a.X / d, a.Y / d, a.Z / d);
		}

		public static bool operator ==(Point a, Point b)
		{
			return (a - b).SqrMagnitude < 9.99999944E-11f;
		}

		public static bool operator !=(Point a, Point b)
		{
			return !(a == b);
		}

		public static Point Zero = new Point(0f, 0f, 0f);

		public static Point One = new Point(1f, 1f, 1f);

		public static Point Forward = new Point(0f, 0f, 1f);

		public static Point Back = new Point(0f, 0f, -1f);

		public static Point Up = new Point(0f, 1f, 0f);

		public static Point Down = new Point(0f, -1f, 0f);

		public static Point Left = new Point(-1f, 0f, 0f);

		public static Point Right = new Point(1f, 0f, 0f);
	}
}
